﻿using System;
using System.Collections.Generic;
using UnityEngine;

namespace FrameWork
{
    public class TimerModule : BaseModule
    {
        /// <summary>
        /// 时间延迟
        /// </summary>
        private Dictionary<int,BaseInfo> _delayInfos;

        /// <summary>
        /// 要被删除的循环缓存
        /// </summary>
        private List<int> _tmpWillRemove;

        private float _curTime;
        private int _curFrame;

        private int _timerId;

        public override void Init()
        {
            _delayInfos = new Dictionary<int, BaseInfo>();
            _tmpWillRemove = new List<int>();
            _curTime = Time.time;
            _curFrame = 0;

            _timerId = 0;
        }

        public override void ShutDown()
        {
            _curTime = 0;
            _curFrame = 0;
            _delayInfos.Clear();
            _tmpWillRemove.Clear();

            _timerId = 0;
        }

        public override void Update(float deltaTime, float realDeltaTime)
        {
            _curTime += deltaTime;
            _curFrame++;
            ExecuteDelays();
        }

        /// <summary>
        /// 延迟一定时间,不带update回调
        /// </summary>
        public int DelayTime(float time, Action callBack)
        {
            var timerInfo = new TimerInfo(time, _curTime, callBack);
            int id = GetNextId();
            _delayInfos.Add(id,timerInfo);
            return id;
        }

        /// <summary>
        /// 延迟时间，带Update回调
        /// </summary>
        public int DelayTime(float time,Action<float,float> updateCb,Action endCb)
        {
            var timeInfo = new TimerInfo(time, _curTime, endCb, updateCb);
            int id = GetNextId();
            _delayInfos.Add(id,timeInfo);
            return id;
        }

        /// <summary>
        /// 延迟帧数，不带Update回调
        /// </summary>
        public int DelayFrame(int frame,Action callBack)
        {
            var frameInfo = new FramerInfo(frame, _curFrame, callBack);
            int id = GetNextId();
            _delayInfos.Add(id,frameInfo);
            return id;
        }

        /// <summary>
        /// 延迟帧数，带Update回调
        /// </summary>
        public int DelayFrame(int frame,Action<int,int> updateCb,Action endCb)
        {
            var frameInfo = new FramerInfo(frame, _curFrame, endCb, updateCb);
            int id = GetNextId();
            _delayInfos.Add(id,frameInfo);
            return id;
        }

        /// <summary>
        /// 循环回调
        /// </summary>
        public int Loop(int interval,Action callBack,int loopCount = 0)
        {
            var loopInfo = new LoopInfo(loopCount, callBack, interval);
            int id = GetNextId();
            _delayInfos.Add(id, loopInfo);
            return id;
        }

        /// <summary>
        /// 处理time延迟
        /// </summary>
        private void ExecuteDelays()
        {
            _tmpWillRemove.Clear();

            foreach (var pair in _delayInfos)
            {
                var timeInfo = pair.Value;

                timeInfo.UpdateTime(_curTime);
                timeInfo.UpdateFrame(_curFrame);

                if (timeInfo.CanInvoke())
                {
                    timeInfo.InvokeUpdate();
                    timeInfo.Invoke();

                    if (timeInfo.CanRemove)
                        _tmpWillRemove.Add(pair.Key);
                }
                else
                {
                    timeInfo.InvokeUpdate();
                }
            }

            if (_tmpWillRemove.Count > 0)
            {
                foreach (int index in _tmpWillRemove)
                {
                    _delayInfos.Remove(index);
                }
            }
        }

        /// <summary>
        /// 获取下一个timerId
        /// </summary>
        private int GetNextId()
        {
            if(_timerId + 1 == int.MaxValue)
            {
                _timerId = 0;
            }

            return ++_timerId;
        }

        /// <summary>
        /// 停止某个回调
        /// </summary>
        public void StopTimer(int timerId)
        {
            if (_delayInfos.ContainsKey(timerId))
                _delayInfos.Remove(_timerId);
        }
    }
}
